home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
tde11.arc
/
BLOCK.C
next >
Wrap
C/C++ Source or Header
|
1991-09-06
|
49KB
|
1,419 lines
/******************* start of original comments ********************/
/*
* Written by Douglas Thomson (1989/1990)
*
* This source code is released into the public domain.
*/
/*
* Name: dte - Doug's Text Editor program - block commands module
* Purpose: This file contains all the commands than manipulate blocks.
* File: block.c
* Author: Douglas Thomson
* System: this file is intended to be system-independent
* Date: October 1, 1989
*/
/********************* end of original comments ********************/
/*
* The block routines have been EXTENSIVELY rewritten. I am not very fond of
* stream blocks. This editor uses LINE blocks and BOX blocks. That is,
* one may either mark entire lines or column blocks. Block operations are
* done in place. There are no paste and cut buffers. In limited memory
* situations, larger block operations can be carried out. Block operations
* can be done within or across files. One disadvantage of not using buffers
* is that block operations can be slow. The most complicated routine in
* this editor is by far "move_copy_delete_overlay_block( window, action )".
* I put some comments in, but it can be hard to understand.
*
* Maybe in the next version I'll use buffers to speed up block operations.
*
* In tde, version 1.1, I separated the BOX and LINE actions. LINE actions
* are a LOT faster, now. Still need to speed up BOX actions.
*
* New editor name: tde, the Thomson-Davis Editor.
* Author: Frank Davis
* Date: June 5, 1991
*
* This modification of Douglas Thomson's code is released into the
* public domain, Frank Davis. You may distribute it freely.
*/
#include "tdestr.h"
#include "common.h"
#include "tdefunc.h"
#include "define.h"
/*
* Name: mark_block
* Purpose: To record the position of the start of the block in the file.
* Date: June 5, 1991
* Passed: window: information required to access current window
* type: type of block LINE or BOX
* Notes: Assume the user will mark begin and end of a block in either
* line mode or box mode. If the user mixes type, then block
* type defaults to LINE.
*/
void mark_block( window, type )
windows *window;
int type;
{
file_infos *file; /* temporary file variable */
int num;
long lnum;
if (g_status.marked == FALSE) {
g_status.marked = TRUE;
g_status.marked_file = window->file_info;
}
file = window->file_info;
g_status.marked_window = window;
/*
* define blocks for only one file. it is ok to modify blocks in any window
* pointing to original marked file.
*/
if (file == g_status.marked_file) {
/*
* mark beginning and ending column regardless of block mode.
*/
if (file->block_type == NOTMARKED) {
file->block_ec = file->block_bc = window->rcol;
file->block_er = file->block_br = window->rline;
} else {
if (file->block_br > window->rline) {
file->block_br = window->rline;
if (file->block_bc < window->rcol)
file->block_ec = window->rcol;
else
file->block_bc = window->rcol;
} else {
file->block_ec = window->rcol;
file->block_er = window->rline;
}
/*
* if user marks ending line less than beginning line then switch
*/
if (file->block_er < file->block_br) {
lnum = file->block_er;
file->block_er = file->block_br;
file->block_br = lnum;
}
/*
* if user marks ending column less than beginning column then switch
*/
if (file->block_ec < file->block_bc) {
num = file->block_ec;
file->block_ec = file->block_bc;
file->block_bc = num;
}
}
/*
* block type in now defined. if user mixes block type then default to
* LINE block.
*/
if (file->block_type == NOTMARKED)
file->block_type = type;
else if (file->block_type == BOX && type == LINE)
file->block_type = LINE;
file->dirty = GLOBAL;
redraw_screen( window );
}
}
/*
* Name: unmark_block
* Purpose: To set all block information to NULL or 0
* Date: June 5, 1991
* Notes: Reset all block variables if marked, otherwise return.
* If a block is unmarked then redraw the screen(s).
*/
void unmark_block( )
{
file_infos *marked_file;
windows *window;
if (g_status.marked == TRUE) {
window = g_status.marked_window;
marked_file = g_status.marked_file;
g_status.marked = FALSE;
g_status.marked_file = NULL;
g_status.marked_window = NULL;
marked_file->block_start = NULL;
marked_file->block_end = NULL;
marked_file->block_bc = marked_file->block_ec = 0;
marked_file->block_br = marked_file->block_er = 0l;
if (marked_file->block_type) {
marked_file->dirty = GLOBAL;
redraw_screen( window );
}
marked_file->block_type = NOTMARKED;
}
}
/*
* Name: restore_marked_block
* Purpose: To restore block beginning and ending row after an editing function
* Date: June 5, 1991
* Passed: window: information required to access current window
* net_change: number of bytes added or subtracted
* Notes: If a change has been made before the marked block then the
* beginning and ending row need to be adjusted by the number of
* lines added or subtracted from file.
*/
void restore_marked_block( window, net_change )
windows *window;
int net_change;
{
file_infos *marked_file;
long length;
if (g_status.marked == TRUE && net_change != 0) {
marked_file = g_status.marked_file;
length = marked_file->length;
/*
* restore is needed only if a block is defined and window->file_info is
* same as marked file and there was a net change in file length.
*/
if (marked_file == window->file_info) {
/*
* if cursor is before marked block then adjust block by net change.
*/
if (marked_file->block_br > window->rline) {
marked_file->block_br += net_change;
marked_file->block_er += net_change;
marked_file->dirty = GLOBAL;
/*
* if cursor is somewhere in marked block don't restore, do redisplay
*/
} else if (marked_file->block_er >= window->rline)
marked_file->dirty = GLOBAL;
/*
* check for lines of marked block beyond end of file
*/
if (marked_file->block_br > length)
unmark_block( );
else if (marked_file->block_er > length) {
marked_file->block_er = length;
marked_file->dirty = GLOBAL;
}
}
}
}
/*
* Name: prepare_block
* Purpose: To prepare a window/file for a block read, move or copy.
* Date: June 5, 1991
* Passed: window: current window
* file: pointer to file information.
* text_line: pointer to line in file to prepare.
* lend: line length.
* bc: beginning column of BOX.
* Notes: The main complication is that the cursor may be beyond the end
* of the current line, in which case extra padding spaces have
* to be added before the block operation can take place.
* This only occurs in BOX operations.
*/
int prepare_block( window, text_line, lend, bc )
windows *window;
text_ptr text_line;
int lend, bc;
{
text_ptr source; /* source for block moves */
text_ptr dest; /* destination for block moves */
file_infos *file; /* temp file pointer */
int pad, i; /* amount of padding to be added */
int number; /* number of characters for block moves */
int prompt_line;
prompt_line = window->bottom_line;
file = window->file_info;
copy_line( text_line, prompt_line );
/*
* work out how much padding is required to extend the current
* line to the cursor position
*/
pad = bc - lend;
/*
* make room for the padding spaces
*/
source = g_status.line_buff + lend;
dest = source + pad;
number = pad + 2;
memmove( dest, source, number );
/*
* insert the padding spaces
*/
for (i=pad; i>0; i--)
*source++ = ' ';
un_copy_line( text_line, window, FALSE );
return( pad );
}
/*
* Name: pad_dest_line
* Purpose: To prepare a window/file for a block move or copy.
* Date: June 5, 1991
* Passed: window: current window
* dest_file: pointer to file information.
* dest_line: pointer to line in file to prepare.
* Notes: We are doing a BOX action (except DELETE). We have come to the
* end of the file and have no more lines. All this routine does
* is add a blank line to file.
*/
void pad_dest_line( window, dest_file, dest_line )
windows *window;
file_infos *dest_file;
text_ptr dest_line;
{
/*
* put linefeed in line_buff. dest_line should be pointing to
* file->end_text - 1. since we inserted line feed, increment file length.
*/
g_status.line_buff[0] = '\n';
g_status.line_buff[1] = CONTROL_Z;
g_status.copied = TRUE;
un_copy_line( dest_line, window, FALSE );
++dest_file->length;
}
/*
* Name: move_copy_delete_overlay_block
* Purpose: Master BOX or LINE routine.
* Date: June 5, 1991
* Passed: window: information required to access current window
* action: action to take on a marked block
* Notes: Operations on BOXs or LINES require several common operations.
* All require finding the beginning and ending marks. The
* big differences are whether to delete the source block, copy the
* source block, or leave the source block marked.
* This routine will handle block operations across files. Since one
* must determine the relationship of source and destination blocks
* within a file, it is relatively easy to expand this relationship
* across files. There are several caveats. Most deal with the
* difference between LINE and BOX operations others deal with
* differences between operations within a file and operations
* across files.
* This is probably the most complicated routine in the editor. It
* is not easy to understand.
*/
void move_copy_delete_overlay_block( window, action )
windows *window;
int action;
{
windows *source_window; /* source window for block moves */
text_ptr source; /* source for block moves */
text_ptr dest; /* destination for block moves */
text_ptr p; /* temporary text pointer */
long number; /* number of characters for block moves */
int lens; /* length of source line */
int lend; /* length of destination line */
int add; /* characters being added from another line */
int block_len; /* length of the block */
text_ptr block_start; /* start of block in file */
text_ptr block_end; /* end of block in file - not same for LINE or BOX */
char block_buff[BUFF_SIZE+2];
int prompt_line;
int same; /* are these files the same */
int source_first; /* is source file lower in memory than dest */
file_infos *source_file, *dest_file;
int rcol, bc, ec; /* temporary column variables */
int xbc, xec; /* temporary column variables */
long rline; /* temporary real line variable */
long br, er, li; /* temporary line variables */
long dest_add; /* number of bytes added to destination file */
long source_sub; /* number of bytes sub from source file */
long diff;
unsigned long block_size;
int block_type;
int fill_char;
int fill_pad; /* number of padding required for FILL or OVERLAY */
windows s_w, d_w; /* a couple of temporary windows for BOX stuff */
/*
* initialize block variables
*/
un_copy_line( window->cursor, window, TRUE );
source_window = g_status.marked_window;
prompt_line = window->bottom_line;
dest_file = window->file_info;
source_file = g_status.marked_file;
check_block( );
if (g_status.marked == FALSE)
return;
block_start = source_file->block_start;
block_end = source_file->block_end;
block_type = source_file->block_type;
dest = window->cursor = cpf( window->cursor );
rline = window->rline;
/*
* if this is a LINE action, put the text below the current line
*/
if (block_type == LINE && action != DELETE)
if ((p = find_next( dest )) != NULL)
dest = p;
/*
* must find out if source and destination file are the same.
* it don't matter with FILL and DELETE - those actions only modify the
* source file.
*/
same = FALSE;
if (action == FILL) {
if (block_type == BOX) {
if (get_block_fill_char( window, &fill_char ) == ERROR)
return;
dest = block_start;
same = TRUE;
} else {
error( WARNING, prompt_line, "can only fill box blocks" );
return;
}
}
if (source_file == dest_file && action != DELETE && action != FILL) {
same = TRUE;
if (block_type == BOX && action == MOVE) {
if (rline == dest_file->block_br &&
(window->rcol >= dest_file->block_bc &&
window->rcol <= dest_file->block_ec))
/*
* a block moved to within the block itself has no effect
*/
return;
} else if (block_type == LINE) {
if (rline >= dest_file->block_br && rline <= dest_file->block_er) {
/*
* if COPYing or KOPYing within the block itself, reposition the
* destination to the next line after the block (if it exists)
*/
if (action == COPY || action == KOPY)
dest = cpf( block_end );
/*
* a block moved to within the block itself has no effect
*/
else if (action == MOVE)
return;
}
}
}
/*
* set up Beginning Column, Ending Column, Beginning Row, Ending Row
*/
bc = source_file->block_bc;
ec = source_file->block_ec;
br = source_file->block_br;
er = source_file->block_er;
/*
* if we are BOX FILLing, beginning column is bc, not the column of cursor
*/
if (action == FILL)
rcol = bc;
else
rcol = window->rcol;
dest_add = source_sub = 0;
/*
* must know if source of block is before or after destination
*/
source_first = FALSE;
if (ptoul( dest ) > ptoul( source_file->block_start ))
source_first = TRUE;
if (same && block_type == BOX) {
if ( rline >= br)
source_first = TRUE;
}
/*
* work out how much has to be moved
*/
if (block_type == BOX) {
block_size = ((ec+1) - bc) * ((er+1) - br);
if (action != DELETE)
block_size += ((rcol+1) * ((er+1) - br));
else
block_size = 0;
} else if (block_type == LINE) {
if (action == COPY || action == KOPY)
block_size = ptoul( block_end ) - ptoul( block_start );
else
block_size = 0;
} else
return;
/*
* check that there is room to add block to file
*/
if (ptoul( g_status.end_mem ) + block_size >= ptoul( g_status.max_mem )) {
error( WARNING, prompt_line, "not enough memory for block" );
return;
}
/*
* 1. can't create lines greater than g_display.line_length
* 2. if we are FILLing a BOX - fill block buff once right here
* 3. only allow overlaying BOXs
*/
if (block_type == BOX) {
block_len = (ec+1) - bc;
if (action != DELETE && action != FILL) {
if (rcol + block_len > g_display.line_length) {
error( WARNING, prompt_line, "line would be too long" );
return;
}
} else if (action == FILL)
block_fill( block_buff, fill_char, block_len );
} else {
block_len = 0;
if (action == OVERLAY) {
error( WARNING, prompt_line, "can only overlay blocks" );
return;
}
}
/*
* all block actions go forward thru file - check those pointers
*/
source = cpf( block_start );
dest = cpf( dest );
if (block_type == LINE) {
diff = ptoul( block_end ) - ptoul( block_start );
dest_add = source_sub = diff;
if (action != DELETE) {
p = addltop( diff, dest );
number = ptoul( g_status.end_mem ) - ptoul( dest );
hw_move( p, dest, number );
g_status.end_mem = addltop( diff, g_status.end_mem);
}
if (action != DELETE && !source_first)
source = addltop( diff, source );
if (action == COPY || action == KOPY || action == MOVE)
hw_move( dest, source, diff );
if (action == DELETE || action == MOVE) {
p = addltop( diff, source );
number = ptoul( g_status.end_mem ) - ptoul( p );
hw_move( source, p, number );
g_status.end_mem = addltop( -diff, g_status.end_mem);
}
if (action == DELETE)
dest_add = 0;
else if (action == COPY || action == KOPY)
source_sub = 0;
diff = (er+1l) - br;
if (action == COPY || action == KOPY || action == MOVE)
dest_file->length += diff;
if (action == DELETE || action == MOVE)
source_file->length -= diff;
if (action == DELETE && source_window->rline >= br) {
source_window->rline -= ((er + 1) - br);
if (source_window->rline < br)
source_window->rline = br;
}
/*
* the block action is now complete. restore all the start_text and
* end_text pointers for all open files.
*/
if (action == MOVE || action == DELETE)
restore_start_end( dest_file, source_file, dest_add, -source_sub,
source_first );
else
restore_start_end( dest_file, source_file, dest_add, source_sub,
source_first );
/*
* restore all cursors in all windows
*/
restore_cursors( dest_file, source_file );
} else {
dup_window_info( &s_w, source_window );
dup_window_info( &d_w, window );
s_w.rline = br;
for (li=br; li<=er; li++, s_w.rline++, d_w.rline++) {
lens = linelen( source );
lend = linelen( dest );
/*
* if we are doing a BOX action and both the source and
* destination are 0 then we have nothing to do. all LINE actions
* require processing.
*/
if (lens != 0 || lend != 0) {
/*
* do actions that may require adding to file
*/
if (action==MOVE || action==COPY || action==KOPY || action==FILL ||
action == OVERLAY) {
d_w.cursor = dest;
if (action != FILL) {
xbc = bc;
xec = ec;
if (action != OVERLAY && block_type == BOX && same) {
if (rcol < bc && rline > br && rline <=er)
if (li >= rline) {
xbc = bc + block_len;
xec = ec + block_len;
}
}
load_buff( block_buff, source, xbc, xec, block_type );
}
add = 0;
if (lend < (rcol+1))
add = prepare_block( &d_w, dest, lend, rcol );
add += copy_buff_2file( &d_w, block_buff, dest, rcol,
block_len, action );
if (!source_first)
source += add;
}
/*
* do actions that may require deleting from file
*/
if (action == MOVE || action == DELETE) {
s_w.cursor = source;
if (lens >= (bc + 1)) {
add = block_len;
xbc = bc;
if (lens <= (ec + 1))
add = lens - bc;
if (same && action == MOVE) {
if (rcol < bc && rline >= br && rline <=er)
if (li >= rline)
xbc = bc + block_len;
}
delete_blocked_block( &s_w, source, xbc, add,
prompt_line );
}
}
}
/*
* if we are doing any BOX action we need to move the source pointer
* to the next line.
*/
source = find_next( source );
/*
* if we are doing any action other than DELETE, we need to move
* the destination to the next line in marked block.
* In BOX mode, we may need to pad the end of the file
* with a blank line before we process the next line.
*/
if (action != DELETE) {
p = find_next( dest );
if (p != NULL)
dest = p;
else {
diff = 0l;
if (source_first || same) {
if (action == MOVE)
diff = dest_add - source_sub;
else
diff = dest_add + source_sub;
} else
diff = dest_add;
p = addltop( -1, dest_file->end_text);
pad_dest_line( window, dest_file, p );
dest = find_next( dest );
}
}
}
}
dest_file->modified = TRUE;
dest_file->dirty = GLOBAL;
if (action == MOVE || action == DELETE || action == FILL) {
source_file->modified = TRUE;
source_file->dirty = GLOBAL;
}
/*
* unless we are doing a KOPY, FILL, or OVERLAY we need to unmark the
* block. if we just did a KOPY, the beginning and ending may have
* changed. so, we must readjust beginning and ending rows.
*/
if (action == KOPY) {
if (same && !source_first && block_type == LINE) {
number = (er+1) - br;
source_file->block_br += number;
source_file->block_er += number;
} else if (same && !source_first && window->rline == br &&
block_type == BOX) {
add = (ec+1) - bc;
source_file->block_bc += add;
source_file->block_ec += add;
}
redraw_screen( window );
} else if (action != FILL && action != OVERLAY)
unmark_block( );
show_avail_mem( );
}
/*
* Name: load_buff
* Purpose: copy the contents of a line in a BOX to the block buffer.
* Date: June 5, 1991
* Passed: block_buff: local buffer for block moves
* source: source line in file
* bc: beginning column of BOX. used only in BOX operations.
* ec: ending column of BOX. used only in BOX operations.
* block_type: LINE or BOX
* Notes: If the block is marked in LINE mode, copy the line to the
* block buffer. If the block is marked in BOX mode, there are
* several things to take care of. 1) The BOX begins and ends
* within a line - just copy the blocked characters to the block buff.
* 2) the BOX begins within a line but ends past the eol - copy
* all the characters within the line to the block buff then fill with
* padding. 3) the BOX begins and ends past eol - fill entire
* block buff with padding.
*/
void load_buff( block_buff, source, bc, ec, block_type )
char *block_buff;
text_ptr source;
int bc, ec, block_type;
{
int len, pad, avlen, i;
len = linelen( source );
if (block_type == LINE) {
if (source[len] == '\n')
++len;
for (i=len; i>0; i++)
*block_buff++ = *source++;
} else {
/*
* block start may be past eol
*/
if (len < ec + 1) {
/*
* does block start past eol? - fill with pad
*/
if (len < bc) {
pad = (ec + 1) - bc;
for (i=pad; i>0; i--)
*block_buff++ = ' ';
} else {
/*
* block ends past eol - fill with pad
*/
pad = (ec + 1) - len;
avlen = len - bc;
source = source + bc;
for (i=avlen; i>0; i--)
*block_buff++ = *source++;
for (i=pad; i>0; i--)
*block_buff++ = ' ';
}
} else {
/*
* block is within line - copy block to buffer
*/
avlen = (ec + 1) - bc;
source = source + bc;
for (i=avlen; i>0; i--)
*block_buff++ = *source++;
}
}
*block_buff++ = CONTROL_Z;
*block_buff = '\0';
}
/*
* Name: copy_buff_2file
* Purpose: copy the contents of block buffer to destination file
* Date: June 5, 1991
* Passed: window: current window
* block_buff: local buffer for moves
* dest: pointer to destination line in destination file
* rcol: if in BOX mode, destination column in destination file
* block_len: if in BOX mode, width of block to copy
* action: type of block action
* Notes: In BOX mode, the destination line has already been prepared.
* Just copy the BOX buffer to the destination line.
*/
int copy_buff_2file( window, block_buff, dest, rcol, block_len, action )
windows *window;
char *block_buff;
text_ptr dest;
int rcol, block_len, action;
{
text_ptr s;
text_ptr d;
long number;
int i;
int prompt_line;
int rc;
rc = 0;
prompt_line = window->bottom_line;
copy_line( dest, prompt_line );
s = g_status.line_buff + rcol;
/*
* s is pointing to location to perform BOX operation. If we do a
* FILL or OVERLAY, we do not necessarily add any extra space. If the
* line does not extend all the thru the BOX then we add.
* we always add space when we COPY, KOPY, or MOVE
*/
if (action == FILL || action == OVERLAY) {
i = linelen( s );
if (i < block_len) {
rc = block_len - i;
d = s + rc;
i = block_len + 1 + linelen( g_status.line_buff ) - rcol;
memmove( d, s, i );
}
} else {
rc = block_len;
d = s + block_len;
i = block_len + 1 + linelen( g_status.line_buff ) - rcol;
memmove( d, s, i );
}
memmove( s, block_buff, block_len );
un_copy_line( dest, window, TRUE );
return( rc );
}
/*
* Name: block_fill
* Purpose: fill the block buffer with character
* Date: June 5, 1991
* Passed: block_buff: local buffer for moves
* fill_char: fill character
* block_len: number of columns in block
* Notes: Fill block_buffer for block_len characters using fill_char. This
* function is used only for BOX blocks.
*/
void block_fill( block_buff, fill_char, block_len)
char *block_buff;
int fill_char;
int block_len;
{
memset( block_buff, fill_char, block_len );
*(block_buff+block_len) = CONTROL_Z;
}
/*
* Name: restore_start_end
* Purpose: a file has been modified - must restore all start and end pointers
* Date: June 5, 1991
* Passed: dest_file: pointer to destination file structure
* source_file: pointer to source file structure
* dest_mod: net modifications in the destination file
* source_mod: net modifications in the source file
* source_first: we must know which file is stored first in memory
* Notes: Go through the file list and adjust the start_text and end_text
* file pointers as needed. There are several cases that must be
* be considered. 1) destination file and source file could be the
* same. 2) if the file pointer we're looking at is below both
* the source and destination, no action is needed. 3) the file
* we're looking at could be between the source and destination.
* 4) the file we're looking at could be either source or destination.
* 5) the file we're looking at could be past both source and dest.
* Use unsigned longs to compare pointers.
*/
void restore_start_end( dest_file, source_file, dest_mod, source_mod,
source_first )
file_infos *dest_file, *source_file;
long dest_mod, source_mod;
int source_first;
{
int same;
long net_mod;
unsigned long sst; /* source start_text - keep these around for if's */
unsigned long dst; /* destination start_text */
unsigned long ost; /* open_file start_text */
file_infos *open_file;
net_mod = dest_mod + source_mod;
sst = ptoul( source_file->start_text );
dst = ptoul( dest_file->start_text );
same = (sst == dst) ? TRUE : FALSE;
for (open_file=g_status.file_list; open_file != NULL;
open_file=open_file->next) {
sst = ptoul( source_file->start_text );
dst = ptoul( dest_file->start_text );
ost = ptoul( open_file->start_text );
if (ost == sst) {
if (same)
source_file->end_text = addltop( net_mod, source_file->end_text);
else if (source_first)
source_file->end_text = addltop( source_mod,
source_file->end_text);
else {
source_file->start_text = addltop( dest_mod,
source_file->start_text);
source_file->end_text = addltop( net_mod, source_file->end_text);
}
} else if (ost == dst) {
if (source_first) {
dest_file->start_text = addltop( source_mod,
dest_file->start_text);
dest_file->end_text = addltop( net_mod, dest_file->end_text);
} else
dest_file->end_text = addltop( dest_mod, dest_file->end_text);
} else if (ost > sst) {
if (ost < dst) {
open_file->start_text = addltop( source_mod,
open_file->start_text);
open_file->end_text = addltop( source_mod, open_file->end_text);
} else {
open_file->start_text = addltop( net_mod, open_file->start_text);
open_file->end_text = addltop( net_mod, open_file->end_text);
}
} else if (ost > dst) {
if (ost < sst) {
open_file->start_text = addltop( dest_mod, open_file->start_text);
open_file->end_text = addltop( dest_mod, open_file->end_text);
} else {
open_file->start_text = addltop( net_mod, open_file->start_text);
open_file->end_text = addltop( net_mod, open_file->end_text);
}
}
}
}
/*
* Name: restore_cursors
* Purpose: a file has been modified - must restore all cursor pointers
* Date: June 5, 1991
* Passed: dest_file: target file for block actions
* source_file: source file for block actions
* Notes: Go through the window list and adjust the cursor pointers
* as needed. This could be done by using the changes made by
* the block actions, but it would be a real pain in the neck.
* I chose to use the brute force approach.
*/
void restore_cursors( dest_file, source_file )
file_infos *dest_file, *source_file;
{
windows *window;
text_ptr p;
file_infos *file;
long beg_line, cur_line, test_line;
unsigned long df, sf, f;
df = ptoul( (text_ptr)dest_file );
sf = ptoul( (text_ptr)source_file );
window = g_status.window_list;
while (window != NULL) {
file = window->file_info;
f = ptoul( (text_ptr)file );
beg_line = 1;
cur_line = window->rline;
if (cur_line > file->length) {
file->end_text = cpb( file->end_text );
p = find_prev( file->end_text-1 );
if (p != NULL )
window->cursor = p;
else
window->cursor = file->start_text;
window->rline = file->length;
test_line = cur_line - file->length;
if (test_line < (long)(window->cline - (window->top_line - 1)))
window->cline -= test_line;
} else {
file->start_text = cpf( file->start_text );
for (p=file->start_text; p!=NULL && beg_line<cur_line; beg_line++)
p = find_next( p );
if (p != NULL )
window->cursor = p;
else {
window->cursor = file->start_text;
cur_line = file->length;
}
window->rline = cur_line;
}
if (window->rline < (window->cline - (window->top_line - 1)))
window->cline = window->rline + window->top_line - 1;
if ((f == df || f == sf) && window->visible )
show_size( window );
window = window->next;
}
}
/*
* Name: delete_blocked_block
* Purpose: delete the marked text
* Date: June 5, 1991
* Passed: s_w: source window
* source: pointer to line with block to delete
* bc: beginning column of block - BOX mode only
* add: number of characters in block to delete
* prompt_line: line to display error message if needed
* Notes: Used only for BOX blocks. Delete the block. Delete any trailing
* blanks at end of line.
*/
void delete_blocked_block( s_w, source, bc, add, prompt_line )
windows *s_w;
text_ptr source;
int bc, add, prompt_line;
{
text_ptr s;
text_ptr d;
int number;
number = linelen( source ) - bc + 2;
copy_line( source, prompt_line );
s = g_status.line_buff + bc + add;
d = s - add;
memmove( d, s, number );
un_copy_line( source, s_w, TRUE );
}
/*
* Name: check_block
* Purpose: To check that the block is still valid.
* Date: June 5, 1991
* Notes: After some editing, the marked block may not be valid. For example,
* deleting all the lines in a block in another window.
*/
void check_block( )
{
file_infos *file;
file = g_status.marked_file;
if (file == NULL || file->block_br > file->length)
unmark_block( );
else {
if (file->length < file->block_er)
file->block_er = file->length;
find_begblock( file );
find_endblock( file );
}
}
/*
* Name: find_begblock
* Purpose: find the beginning line in file with marked block
* Date: June 5, 1991
* Passed: file: file containing marked block
* Notes: file->block_start contains starting line of marked block at end.
*/
void find_begblock( file )
file_infos *file;
{
text_ptr next; /* start from beginning of file and go to end */
long i; /* line counter */
next = cpf( file->start_text );
for (i=1; i<file->block_br && next != NULL; i++)
next = find_next( next );
if (next != NULL)
file->block_start = next;
}
/*
* Name: find_endblock
* Purpose: find the ending line in file with marked block
* Date: June 5, 1991
* Passed: file: file containing marked block
* Notes: If in LINE mode, file->block_end is set to end of line of last
* line in block. If in BOX mode, file->block_end is set to
* beginning of last line in marked block. If the search for the
* ending line of the marked block goes past the eof, set the
* ending line of the block to the last line in the file.
*/
void find_endblock( file )
file_infos *file;
{
text_ptr next; /* start from beginning of file and go to end */
long i; /* line counter */
int end_column;
next = cpf( file->start_text );
for (i=1; i<file->block_er && next != NULL; i++)
next = find_next( next );
if (next != NULL) {
end_column = linelen( next );
if (next[end_column] == '\n')
++end_column;
if (file->block_type == LINE)
file->block_end = next + end_column;
else
file->block_end = next;
} else {
file->end_text = cpb( file->end_text );
if (file->block_type == LINE)
file->block_end = file->end_text - 1;
else {
next = find_prev( file->end_text - 1 );
if (next != NULL)
file->block_end = next;
else
file->block_end = file->end_text - 1;
}
file->block_er = file->length;
}
}
/*
* Name: block_write
* Purpose: To write the currently marked block to a disk file.
* Date: June 5, 1991
* Passed: window: information required to access current window
* Notes: If the file already exists, the user gets to choose whether
* to overwrite or append.
*/
void block_write( window )
windows *window;
{
int prompt_line;
int rc;
char buff[MAX_COLS+2]; /* buffer for char and attribute */
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
text_ptr block_start; /* start of block in file */
text_ptr block_end; /* end of block in file */
file_infos *file;
int block_type;
/*
* make sure block is marked OK
*/
un_copy_line( window->cursor, window, TRUE );
check_block( );
if (g_status.marked == TRUE) {
prompt_line = window->bottom_line;
file = window->file_info;
block_start = file->block_start;
block_end = file->block_end;
block_type = file->block_type;
/*
* find out which file to write to
*/
save_screen_line( 0, prompt_line, line_buff );
if (get_name( "Filename: ", prompt_line, g_status.rw_name,
g_display.message_color ) == OK) {
/*
* if the file exists, find out whether to overwrite or append
*/
if (hw_fattrib( g_status.rw_name ) != ERROR) {
set_prompt( "File exists. Overwrite or Append? (o/a): ",
prompt_line );
switch (get_oa( )) {
case A_OVERWRITE :
hw_unlink( g_status.rw_name, prompt_line );
combine_strings( buff, "writing block to '",
g_status.rw_name, "'" );
s_output( buff, prompt_line, 0, g_display.message_color );
rc = hw_save( g_status.rw_name, block_start, block_end,
block_type, prompt_line );
if (rc == ERROR)
error( WARNING, prompt_line, "could not write block" );
break;
case A_APPEND :
combine_strings( buff, "appending block to '",
g_status.rw_name, "'" );
s_output( buff, prompt_line, 0, g_display.message_color );
rc = hw_append( g_status.rw_name, block_start, block_end,
block_type, prompt_line );
if (rc == ERROR)
error( WARNING, prompt_line, "could not append block" );
break;
}
} else {
combine_strings( buff, "writing block to '", g_status.rw_name,
"'" );
s_output( buff, prompt_line, 0, g_display.message_color );
if (hw_save( g_status.rw_name, block_start, block_end,
block_type, prompt_line ) == ERROR)
error( WARNING, prompt_line, "could not write block" );
}
}
restore_screen_line( 0, prompt_line, line_buff );
}
}
/*
* Name: block_print
* Purpose: Print an entire file or the currently marked block.
* Date: June 5, 1991
* Passed: window: information required to access current window
*/
void block_print( window )
windows *window;
{
char answer[MAX_COLS]; /* entire file or just marked block? */
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
int col, func;
int prompt_line;
text_ptr block_start; /* start of block in file */
text_ptr block_end; /* end of block in file */
file_infos *file;
int block_type;
un_copy_line( window->cursor, window, TRUE );
prompt_line = window->bottom_line;
save_screen_line( 0, prompt_line, line_buff );
/*
* print entire file or just marked block?
*/
strcpy( answer, "Print file or block? (f/b): " );
col = strlen( answer );
s_output( answer, prompt_line, 0, g_display.message_color );
eol_clear( col, prompt_line, g_display.text_color );
xygoto( col, prompt_line );
func = col = 0;
while (col != 'f' && col != 'F' && col != 'b' && col != 'B' && func != ESC) {
col = getkey( );
func = getfunc( col );
}
if (func != ESC) {
file = window->file_info;
if (col == 'f' || col == 'F') {
strcpy( answer, "Printing file..." );
block_start = file->start_text;
block_end = cpb( file->end_text ) - 1;
block_type = NOTMARKED;
} else if (col == 'b' || col == 'B') {
check_block( );
if (g_status.marked == TRUE) {
strcpy( answer, "Printing block..." );
block_start = file->block_start;
block_end = file->block_end;
block_type = file->block_type;
} else
col = ESC;
}
if (col != ESC) {
col = strlen( answer );
s_output( answer, prompt_line, 0, g_display.message_color );
eol_clear( col, prompt_line, g_display.text_color );
if (hw_print( block_start, block_end, block_type, prompt_line ))
error( WARNING, prompt_line, "error in printing text" );
}
}
restore_screen_line( 0, prompt_line, line_buff );
}
/*
* Name: get_block_fill_char
* Purpose: get the character to fill marked block.
* Date: June 5, 1991
* Passed: window: information required to access current window
* c: address of character to fill block
*/
int get_block_fill_char( window, c )
windows *window;
int *c;
{
char answer[MAX_COLS]; /* entire file or just marked block? */
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
int col;
int prompt_line;
int rc;
rc = OK;
prompt_line = window->bottom_line;
save_screen_line( 0, prompt_line, line_buff );
strcpy( answer, "Enter character to fill block (ESC to exit): " );
s_output( answer, prompt_line, 0, g_display.message_color );
col = strlen( answer );
eol_clear( col, prompt_line, g_display.text_color );
xygoto( col, prompt_line );
col = getkey( );
if (col >= 256)
rc = ERROR;
else
*c = col;
restore_screen_line( 0, prompt_line, line_buff );
return( rc );
}
/*
* Name: block_expand_tabs
* Purpose: Expand tabs in a marked block.
* Date: June 5, 1991
* Passed: window: pointer to current window
* Notes: Tabs are expanded using the current tab interval.
* Lines are checked to make sure they are not too long.
*/
void block_expand_tabs( window )
windows *window;
{
int prompt_line;
int len;
int tab;
int tab_size;
int dirty;
int spaces;
int net_change;
text_ptr p; /* pointer to block line */
file_infos *file;
windows s_w;
int block_type;
long er, li;
int bc, ec, tc;
int i, j;
char exp_buff[BUFF_SIZE+2], *b, *q, *s, *d, *lb;
/*
* make sure block is marked OK
*/
un_copy_line( window->cursor, window, TRUE );
check_block( );
if (g_status.marked == TRUE) {
/*
* initialize everything
*/
prompt_line = window->bottom_line;
dirty = FALSE;
tab_size = g_status.tab_size;
file = g_status.marked_file;
bc = file->block_bc;
ec = file->block_ec;
p = cpf( file->block_start );
block_type = file->block_type;
er = file->block_er;
dup_window_info( &s_w, g_status.marked_window );
lb = g_status.line_buff;
for (s_w.rline = li = file->block_br; li<=er; li++, s_w.rline++) {
/*
* use the line buffer to expand LINE blocks.
* use the line buffer and the exp buffer to expand BOX blocks.
*/
tab = FALSE;
len = linelen( p );
net_change = 0;
g_status.copied = FALSE;
if (block_type == BOX) {
if (len > bc) {
/*
* copy the line starting at the beginning column of BOX to the
* line buffer.
*/
copy_line( p+bc, prompt_line);
b = lb;
/*
* put the characters in the BOX in the exp_buff.
*/
for (j=0,i=bc; i<= ec && i<len; i++,j++)
exp_buff[j] = *b++;
exp_buff[j] = CONTROL_Z;
/*
* now, delete all characters in BOX from line buffer.
*/
b = lb;
i = (ec < len) ? ec+1 : len;
i -= bc;
s = b + i;
j = linelen( s ) + 3;
memmove( b, s, j );
/*
* expand the tabs in the line buffer.
*/
b = exp_buff;
for (b=exp_buff, i=bc+1; *b != CONTROL_Z; b++) {
if (*b == '\t') {
tab = TRUE;
spaces = i % tab_size;
if (spaces)
spaces = tab_size - spaces;
if (spaces) {
d = b + spaces;
j = linelen( b ) + 2;
memmove( d, b, j );
}
for (j=0; j<=spaces; j++)
*(b+j) = ' ';
net_change += spaces;
i += spaces + 1;
b += spaces;
} else
i++;
}
if (tab == TRUE) {
/*
* make room in the line buffer for the expanded tabs.
*/
i = linelen( exp_buff );
s = lb;
j = linelen( s ) + 2;
d = s + i;
memmove( d, s, j );
for (q=s, b=exp_buff; *b != CONTROL_Z;)
*q++ = *b++;
un_copy_line( p+bc, &s_w, TRUE );
}
}
} else if (block_type == LINE) {
/*
* LINE blocks are easy. copy the line into the line buffer (lb)
* and expand the tabs if any.
*/
copy_line( p, prompt_line);
for (b=lb, i=1; *b != CONTROL_Z; b++) {
if (*b == '\t') {
tab = TRUE;
spaces = i % tab_size;
if (spaces)
spaces = tab_size - spaces;
if (spaces) {
d = b + spaces;
j = linelen( b ) + 2;
memmove( d, b, j );
}
for (j=0; j<=spaces; j++)
*(b+j) = ' ';
net_change += spaces;
i += spaces + 1;
b += spaces;
} else
i++;
}
if (tab == TRUE)
un_copy_line( p, &s_w, TRUE );
}
if (tab == TRUE)
dirty = GLOBAL;
p = find_next( p );
}
/*
* IMPORTANT: we need to reset the copied flag because the cursor may
* not necessarily be on the last line of the block.
*/
g_status.copied = FALSE;
if (dirty) {
check_block( );
g_status.marked_file->dirty = dirty;
show_avail_mem( );
}
}
}